home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1993, 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*
- rubber.c
- Drew Olbrich, 1992
- */
-
- #include <stdio.h>
- #include <math.h>
- #include <gl.h>
- #include <device.h>
-
- #include "defs.h"
- #include "rubber.h"
-
- EFFECT rubber = { rubber_init, rubber_dynamics, rubber_redraw, rubber_click };
-
- #define SPRING_KS 0.3
- #define DRAG 0.5
-
- typedef struct {
- float x[3];
- float v[3];
- float t[2];
- int nail;
- } MASS;
-
- typedef struct {
- int i, j;
- float r;
- } SPRING;
-
- static int spring_count;
-
- static MASS *mass = NULL;
- static SPRING *spring = NULL;
-
- static int grab = -1; /* index of grabbed mass point */
-
- void rubber_init()
- {
- int i, j;
- int k;
- int m;
-
- zbuffer(TRUE);
-
- if (mass == NULL)
- {
- mass = (MASS *) malloc(sizeof(MASS)*GRID_SIZE_X*GRID_SIZE_Y);
- if (mass == NULL)
- {
- fprintf(stderr, "rubber: Can't allocate memory.\n");
- exit(-1);
- }
- }
-
- k = 0;
- for (i = 0; i < GRID_SIZE_X; i++)
- for (j = 0; j < GRID_SIZE_Y; j++)
- {
- mass[k].nail = (i == 0 || j == 0 || i == GRID_SIZE_X - 1
- || j == GRID_SIZE_Y - 1);
- mass[k].x[0] = i/(GRID_SIZE_X - 1.0)*WIN_SIZE_X;
- mass[k].x[1] = j/(GRID_SIZE_Y - 1.0)*WIN_SIZE_Y;
- mass[k].x[2] = -(CLIP_FAR - CLIP_NEAR)/2.0;
-
- mass[k].v[0] = 0.0;
- mass[k].v[1] = 0.0;
- mass[k].v[2] = 0.0;
-
- mass[k].t[0] = i/(GRID_SIZE_X - 1.0);
- mass[k].t[1] = j/(GRID_SIZE_Y - 1.0);
-
- k++;
- }
-
- if (spring == NULL)
- {
- spring_count = (GRID_SIZE_X - 1)*(GRID_SIZE_Y - 2)
- + (GRID_SIZE_Y - 1)*(GRID_SIZE_X - 2);
-
- spring = (SPRING *) malloc(sizeof(SPRING)*spring_count);
- if (spring == NULL)
- {
- fprintf(stderr, "rubber: Can't allocate memory.\n");
- exit(-1);
- }
- }
-
- k = 0;
- for (i = 1; i < GRID_SIZE_X - 1; i++)
- for (j = 0; j < GRID_SIZE_Y - 1; j++)
- {
- m = GRID_SIZE_Y*i + j;
- spring[k].i = m;
- spring[k].j = m + 1;
- spring[k].r = (WIN_SIZE_Y - 1.0)/(GRID_SIZE_Y - 1.0);
- k++;
- }
-
- for (j = 1; j < GRID_SIZE_Y - 1; j++)
- for (i = 0; i < GRID_SIZE_X - 1; i++)
- {
- m = GRID_SIZE_Y*i + j;
- spring[k].i = m;
- spring[k].j = m + GRID_SIZE_X;
- spring[k].r = (WIN_SIZE_X - 1.0)/(GRID_SIZE_X - 1.0);
- k++;
- }
- }
-
- /*
- Do the dynamics simulation for the next frame.
- */
-
- void rubber_dynamics(int mousex, int mousey)
- {
- int k;
- float d[3];
- int i, j;
- float l;
- float a;
-
- /* calculate all the spring forces acting on the mass points */
-
- for (k = 0; k < spring_count; k++)
- {
- i = spring[k].i;
- j = spring[k].j;
-
- d[0] = mass[i].x[0] - mass[j].x[0];
- d[1] = mass[i].x[1] - mass[j].x[1];
- d[2] = mass[i].x[2] - mass[j].x[2];
-
- l = sqrt(d[0]*d[0] + d[1]*d[1] + d[2]*d[2]);
-
- if (l != 0.0)
- {
- d[0] /= l;
- d[1] /= l;
- d[2] /= l;
-
- a = l - spring[k].r;
-
- mass[i].v[0] -= d[0]*a*SPRING_KS;
- mass[i].v[1] -= d[1]*a*SPRING_KS;
- mass[i].v[2] -= d[2]*a*SPRING_KS;
-
- mass[j].v[0] += d[0]*a*SPRING_KS;
- mass[j].v[1] += d[1]*a*SPRING_KS;
- mass[j].v[2] += d[2]*a*SPRING_KS;
- }
- }
-
- /* update the state of the mass points */
-
- for (k = 0; k < GRID_SIZE_X*GRID_SIZE_Y; k++)
- if (!mass[k].nail)
- {
- mass[k].x[0] += mass[k].v[0];
- mass[k].x[1] += mass[k].v[1];
- mass[k].x[2] += mass[k].v[2];
-
- mass[k].v[0] *= (1.0 - DRAG);
- mass[k].v[1] *= (1.0 - DRAG);
- mass[k].v[2] *= (1.0 - DRAG);
-
- if (mass[k].x[2] > -CLIP_NEAR - 0.01)
- mass[k].x[2] = -CLIP_NEAR - 0.01;
- if (mass[k].x[2] < -CLIP_FAR + 0.01)
- mass[k].x[2] = -CLIP_FAR + 0.01;
- }
-
- /* if a mass point is grabbed, attach it to the mouse */
-
- if (grab != -1 && !mass[grab].nail)
- {
- mass[grab].x[0] = mousex;
- mass[grab].x[1] = mousey;
- mass[grab].x[2] = -(CLIP_FAR - CLIP_NEAR)/4.0;
- }
- }
-
- /*
- Draw the next frame of animation.
- */
-
- void rubber_redraw()
- {
- int k;
- int i, j;
-
- zclear();
-
- cpack(0xFFFFFFFF);
-
- #define _WIREFRAME
- #ifdef WIREFRAME
- for (k = 0; k < spring_count; k++)
- {
- bgnline();
- v3f(mass[spring[k].i].x);
- v3f(mass[spring[k].j].x);
- endline();
- }
- #else
- k = 0;
- for (i = 0; i < GRID_SIZE_X - 1; i++)
- {
- for (j = 0; j < GRID_SIZE_Y - 1; j++)
- {
- bgnpolygon();
- t2f(mass[k].t);
- v3f(mass[k].x);
- t2f(mass[k + 1].t);
- v3f(mass[k + 1].x);
- t2f(mass[k + GRID_SIZE_Y + 1].t);
- v3f(mass[k + GRID_SIZE_Y + 1].x);
- t2f(mass[k + GRID_SIZE_Y].t);
- v3f(mass[k + GRID_SIZE_Y].x);
- endpolygon();
- k++;
- }
- k++;
- }
- #endif
-
- swapbuffers();
- }
-
- /*
- Return the index of the mass point that's nearest to the
- given screen coordinate.
- */
-
- int rubber_grab(int x, int y)
- {
- float dx[2];
- float d;
- float min_d;
- float min_i;
- int i;
-
- for (i = 0; i < GRID_SIZE_X*GRID_SIZE_Y; i++)
- {
- dx[0] = mass[i].x[0] - x;
- dx[1] = mass[i].x[1] - y;
- d = sqrt(dx[0]*dx[0] + dx[1]*dx[1]);
- if (i == 0 || d < min_d)
- {
- min_i = i;
- min_d = d;
- }
- }
-
- return min_i;
- }
-
- /*
- If the mouse is pressed down, grab the nearest mass point.
- */
-
- void rubber_click(int mousex, int mousey, int state)
- {
- if (state)
- grab = rubber_grab(mousex, mousey);
- else
- grab = -1;
- }
-